#include "player.h"

#include "items.h"
#include "maps.h"
#include "messagecontroller.h"
#include "coordinates.h"
#include "view.h"

using namespace fortress;

player::player():requestRedraw(0), turns(0)
{
	AI=0;
}

player::player(int setStrength, int setIntelligence, int setDexterity, int setConstitution, int setCharisma, int setLuck, view * setView)
{
	setStats(setStrength, setIntelligence, setDexterity, setConstitution, setCharisma, setLuck);
	gameView = setView;
	setHealth(10,10);
	AI=0;
}

player::~player()
{

}

void player::explore()
{
	int a,b;
	getCoords(a,b);
	currentMap->calculateVisibility(a,b);
}

bool player::exec(int a, int b)
{
	COORD temp;
	temp.x=0;
	temp.y=0;
	bool status;
	switch(a)
	{
	case event_move:
		temp = temp + (moveDirections)b;
		status = character::move(temp.x, temp.y);
//		explore();
		return status;
	case event_quit:	// display some sort of y/n menu
		return 1;
	case event_open:
		return sendEvent((playerEvents)a,(moveDirections)b);
	case event_close:
		return sendEvent((playerEvents)a,(moveDirections)b);
	case event_pickup:
		return pickupItem();
	case event_drop:
		return dropItem();
	case event_stairs:
		if (useStairs(b))
		{
			gameView->setMap(currentMap);
			return 1;
		}
		return 0;
	case event_inventory:
		showInventory();
		return 0;	// never takes a turn
	}
	return 0;
}

bool player::doEvent(eventStructure const & sent)
{
	switch(sent.type)
	{
	case event_attack:
		message("You were hit!");
		receiveAttack(sent.degree);
		return 1;
	}
	return 0;
}

bool player::sendEvent(playerEvents doAction, moveDirections dir)
{
	COORD temp;
	getCoords(temp.x,temp.y);
	temp = temp + dir;
	eventStructure newEvent(this, this, doAction, 0, temp.x, temp.y);
	return currentMap->fireEventOnTile(newEvent);
}

void player::sense(eventStructure const & sent, character const & target, bool eyeshot, bool adjacent)
{
	if (eyeshot /*&& canSee*/)
	{
		character * tempChar = (character*)sent.sentFrom;
		std::string newMessage;
		switch(sent.type)
		{
		case event_attack:
			newMessage += target.getGlyph();
			newMessage += " was hit!";
			message(newMessage);
			break;
		case event_death:
			newMessage += target.getGlyph();
			newMessage += " has died!";
			message(newMessage);
		}
	}
}

void player::showInventory()
{
	std::vector<std::string*> display;
	for (std::list<items*>::iterator it=inventory.begin(); it!= inventory.end(); it++)
	{
		std::string * getter = new std::string((*it)->getSingular());
		display.push_back(getter);
	}
 	gameView->drawMenu(display, std::string("Inventory"),1);
}

bool player::pickupItem()
{
	int a,b;
	getCoords(a,b);
	std::list<items*> const * tempList = currentMap->getItemList(a,b);
	if (tempList==0)
		return 0;
	std::list<items*> copyList;
	std::vector<std::string*> display;
	for (std::list<items*>::const_iterator it=tempList->begin(); it!= tempList->end(); it++)
	{
		items const * tempItem = *it;
		if (tempItem->getCanCarry())
		{
			std::string * getter = new std::string(tempItem->getSingular());
			display.push_back(getter);
			copyList.push_back(*it);
		}
	}
	if (copyList.size()==0)
		return 0;
	std::vector<int> getItems = gameView->drawMenu(display, std::string("You see the following items. What do you want to pick up?"));
	for (std::vector<std::string*>::iterator it = display.begin(); it!=display.end(); it++)
	{
		delete *it;
	}
	display.clear();
	int i=0;
	if (getItems.size()!=0)
	{
		for (std::list<items*>::const_iterator it=copyList.begin(); it!=copyList.end(); it++)
		{
			if (getItems[i]==1)
			{
				items const * tempItem = *it;
				if (tempItem->getCanCarry())
				{
					items & newItem = currentMap->pickupItem(a,b,tempItem);
					inventory.push_back(&newItem);
				}
			}
			i++;
		}
	}
	else
	{
		return 0;
	}
	return 1;
}

void player::setHealth(int newHp, int newMaxHp)
{
	character::setHealth(newHp, newMaxHp);
	gameView->drawHealth(getHp(), getMaxHp());
}

void player::adjustHealth(int amt)
{
	character::adjustHealth(amt);
	gameView->drawHealth(getHp(), getMaxHp());
}

void player::message(std::string const & message)
{
	messageController & messages = messageController::getInstance();
	messages.addMessage(message);
}

void player::setView(view * newView)
{
	gameView = newView; 
	gameView->setMap(currentMap);
	adjustHealth(0); 
}

template<class Archive>
void player::serialize(Archive & ar, const unsigned int version)
{
	ar & boost::serialization::base_object<character>(*this);
	ar & turns;
}

template void player::serialize<boost::archive::binary_oarchive>(boost::archive::binary_oarchive & ar, const unsigned int version);
template void player::serialize<boost::archive::text_oarchive>(boost::archive::text_oarchive & ar, const unsigned int version);
template void player::serialize<boost::archive::text_iarchive>(boost::archive::text_iarchive & ar, const unsigned int version);